package com.xuzz.study.thread;

import sun.misc.Unsafe;

import java.lang.reflect.Constructor;

public class CLH {

    private static final Unsafe unsafe ;
    private static final long headOffset;
    private static final long tailOffset;


    static {
        try {

            Constructor<Unsafe> constructor = Unsafe.class.getDeclaredConstructor(new Class<?>[0]);

            constructor.setAccessible(true);

            unsafe = constructor.newInstance(new Object[0]);

            headOffset = unsafe.objectFieldOffset
                    (CLH.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset
                    (CLH.class.getDeclaredField("tail"));


        } catch (Exception ex) { throw new Error(ex); }
    }

    /**
     * FIFO的双向同步队列
     */

    final class Node
    {
        Node next;
        Node prev;
        String name;
        Node(String name){
            this.name = name;
        }
    }

    Node head;
    Node tail;

    public void addNode(String name)
    {
        Node node = new Node(name);
        Node pred = tail;
        if(null!=pred)
        {
            node.prev = pred;

            if(compareAndSetTail(pred,node)) {
                pred.next = node;
                return;
            }
        }

        for(;;)
        {
            Node t = tail;
            if(null==t)
            {
                if(compareAndSetHead(null,node))
                {
                    tail = head;
                }
            }
            else
            {
                if(compareAndSetTail(t,node))
                {
                    t.next=node;
                    return ;
                }
            }
        }
    }

    private final boolean compareAndSetTail(Node oldTail,Node newTail)
    {
        return unsafe.compareAndSwapObject(this,tailOffset,oldTail,newTail);
    }

    private final boolean compareAndSetHead(Node oldTail,Node newTail)
    {
        return unsafe.compareAndSwapObject(this,headOffset,oldTail,newTail);
    }

    public Node pollNode()
    {
        if(null==head)
        {
            return null;
        }

        Node pred = head;
        head = pred.next;
        return pred;
    }

    public static void main(String[] args)
    {
        CLH c = new CLH();
        c.addNode("a");
        c.addNode("b");
        c.addNode("c");

        System.out.println(c.pollNode().name);
        System.out.println(c.pollNode().name);
        System.out.println(c.pollNode().name);
    }
}
